package com.suke.czx.modules.performanceconfig.controller;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.suke.czx.common.annotation.SysLog;
import com.suke.czx.common.base.AbstractController;
import com.suke.czx.common.utils.*;
import com.suke.czx.common.validate.PerformanceConfigCopyGroup;
import com.suke.czx.common.validate.PerformanceConfigMarginAndNoteUpdateGroup;
import com.suke.czx.common.validate.PerformanceConfigSaveGroup;
import com.suke.czx.common.validate.PerformanceConfigUpdateGroup;
import com.suke.czx.modules.performanceconfig.entity.PerformanceConfig;
import com.suke.czx.modules.performanceconfig.entity.PerformanceConfigSearchBo;
import com.suke.czx.modules.performanceconfig.entity.SimulationParam;
import com.suke.czx.modules.performanceconfig.service.PerformanceConfigService;
import io.swagger.annotations.Api;
import lombok.AllArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 应用模块名称: 绩效参数
 * 代码描述: 绩效参数控制层
 * copyright: AUZAR ALL RIGHTS RESERVED
 * company: AUZAR
 *
 * @author: 颜米晨
 * @date: 2022/06/11 14:20
 */
@Validated
@RestController
@RequestMapping("/api/performanceConfig")
@AllArgsConstructor
@Api(value = "PerformanceConfigController", tags = "绩效参数管理")
public class PerformanceConfigController extends AbstractController {

    private final PerformanceConfigService performanceConfigService;

    /**
     * 获取绩效年份及版本
     * @return VO
     */
    @RequestMapping(value = "/yearVersion", method = RequestMethod.POST)
    @PreAuthorize("hasRole('but:performanceConfig:yearVersion')")
    public R yearVersion() {
        Map<String, Object> yearVersionMap = performanceConfigService.yearVersion();
        return R.ok().setData(yearVersionMap);
    }

    /**
     * 获取绩效参数详情
     * @param performanceConfigSearchBo 绩效参数查询BO
     * @return VO
     */
    @RequestMapping(value = "/info", method = RequestMethod.POST)
    @PreAuthorize("hasRole('but:performanceConfig:info')")
    public R info(PerformanceConfigSearchBo performanceConfigSearchBo) {
        // 返回结果
        PerformanceConfig performanceConfig = new PerformanceConfig();
        // 过滤条件
        QueryWrapper<PerformanceConfig> queryWrapper = new QueryWrapper<>();
        // 根据年份,版本,岗位1,岗位2查询精确参数配置(生产岗位只传job1)
        queryWrapper
                .eq(FieldConstant.DEL_FLG, CodeConstant.NOT_DEL)
                .eq(!StrUtil.isBlankIfStr(performanceConfigSearchBo.getYear()), FieldConstant.YEAR, performanceConfigSearchBo.getYear())
                .eq(!StrUtil.isBlankIfStr(performanceConfigSearchBo.getVersion()), FieldConstant.VERSION, performanceConfigSearchBo.getVersion())
                .eq(!StrUtil.isBlankIfStr(performanceConfigSearchBo.getJob1()), FieldConstant.JOB_1, performanceConfigSearchBo.getJob1())
                .eq(!StrUtil.isBlankIfStr(performanceConfigSearchBo.getJob2()), FieldConstant.JOB_2, performanceConfigSearchBo.getJob2());
        List<PerformanceConfig> dataList = performanceConfigService.list(queryWrapper);
        // 如果未查询到精确参数配置,则查询该年本,版本下的毛利率去除率和备注
        if (ListUtil.isEmpty(dataList)) {
            QueryWrapper<PerformanceConfig> queryWrapperExt = new QueryWrapper<>();
            queryWrapperExt
                    .eq(FieldConstant.DEL_FLG, CodeConstant.NOT_DEL)
                    .eq(!StrUtil.isBlankIfStr(performanceConfigSearchBo.getYear()), FieldConstant.YEAR, performanceConfigSearchBo.getYear())
                    .eq(!StrUtil.isBlankIfStr(performanceConfigSearchBo.getVersion()), FieldConstant.VERSION, performanceConfigSearchBo.getVersion());
            dataList = performanceConfigService.list(queryWrapperExt);
            if (!ListUtil.isEmpty(dataList)) {
                performanceConfig.setMarginRemovalRate(dataList.get(0).getMarginRemovalRate());
                performanceConfig.setNote(dataList.get(0).getNote());
            }
        } else {
            if (NumUtil.null2Zero( performanceConfigSearchBo.getJob1()) == CodeConstant.PERFORMANCE_PRODUCTION) {
                // 如果是生产岗位拼接合并对象
                buildProductionConfig(dataList, performanceConfig);
            } else {
                performanceConfig = dataList.get(0);
            }
        }
        return ListUtil.isEmpty(dataList) ? R.ok() : R.ok().setData(performanceConfig);
    }

    /**
     * 保存绩效参数
     * @param performanceConfig 绩效参数
     * @param bindingResult bindingResult
     * @return VO
     */
    @SysLog("保存绩效参数")
    @RequestMapping(value = "/save", method = RequestMethod.POST)
    @PreAuthorize("hasRole('but:performanceConfig:save')")
    public R save(@Validated(PerformanceConfigSaveGroup.class) PerformanceConfig performanceConfig, BindingResult bindingResult) {
        // 入参校验结果
        if (bindingResult.hasErrors()) {
            return R.error(ParamValidateUtil.paramVilated(bindingResult));
        }
        if (NumUtil.null2Zero(performanceConfig.getJob1()) == CodeConstant.PERFORMANCE_PRODUCTION) {
            // 如果是生产岗位拆分合并对象
            List<PerformanceConfig> dataList = parseProductionConfig(performanceConfig, CommonConstant.SAVE_MODE);
            dataList.forEach(performanceConfigService::savePerformanceConfig);
        } else {
            performanceConfig.setCreator(getUserId());
            performanceConfig.setCreateTime(new Date());
            performanceConfigService.savePerformanceConfig(performanceConfig);
        }
        return R.ok();
    }

    /**
     * 更新绩效参数
     * @param performanceConfig 绩效参数
     * @param bindingResult bindingResult
     * @return VO
     */
    @SysLog("更新绩效参数")
    @RequestMapping(value = "/update", method = RequestMethod.POST)
    @PreAuthorize("hasRole('but:performanceConfig:update')")
    public R update(@Validated(PerformanceConfigUpdateGroup.class) PerformanceConfig performanceConfig, BindingResult bindingResult) {
        // 入参校验结果
        if (bindingResult.hasErrors()) {
            return R.error(ParamValidateUtil.paramVilated(bindingResult));
        }
        // 毛利率去除率和备注不可更新
        performanceConfig.setMarginRemovalRate(null);
        performanceConfig.setNote(null);
        if (NumUtil.null2Zero(performanceConfig.getJob1()) == CodeConstant.PERFORMANCE_PRODUCTION) {
            // 如果是生产岗位拆分合并对象
            List<PerformanceConfig> dataList = parseProductionConfig(performanceConfig, CommonConstant.UPDATE_MODE);
            dataList.forEach(performanceConfigService::updateById);
        } else {
            performanceConfig.setUpdater(getUserId());
            performanceConfig.setUpdateTime(new Date());
            performanceConfigService.updateById(performanceConfig);
        }
        return R.ok();
    }

    /**
     * 批量更新同一年份版本下的毛利率去除率和备注
     * @param performanceConfig 绩效参数
     * @param bindingResult bindingResult
     * @return VO
     */
    @SysLog("更新毛利率去除率和备注")
    @RequestMapping(value = "/updateRemovalAndNote", method = RequestMethod.POST)
    @PreAuthorize("hasRole('but:performanceConfig:updateRemovalAndNote')")
    public R updateRemovalAndNote(@Validated(PerformanceConfigMarginAndNoteUpdateGroup.class) PerformanceConfig performanceConfig, BindingResult bindingResult) {
        // 入参校验结果
        if (bindingResult.hasErrors()) {
            return R.error(ParamValidateUtil.paramVilated(bindingResult));
        }
        performanceConfig.setUpdater(getUserId());
        performanceConfig.setUpdateTime(new Date());
        return performanceConfigService.updateMarginRemovalRateAndNote(performanceConfig);
    }

    /**
     * 复制绩效配置参数
     * @param performanceConfig 绩效参数
     * @param bindingResult bindingResult
     * @return VO
     */
    @SysLog("复制绩效参数")
    @RequestMapping(value = "/copy", method = RequestMethod.POST)
    @PreAuthorize("hasRole('but:performanceConfig:copy')")
    public R copy(@Validated(PerformanceConfigCopyGroup.class) PerformanceConfig performanceConfig, BindingResult bindingResult) {
        // 入参校验结果
        if (bindingResult.hasErrors()) {
            return R.error(ParamValidateUtil.paramVilated(bindingResult));
        }
        performanceConfig.setCreator(getUserId());
        performanceConfig.setCreateTime(new Date());
        return performanceConfigService.copyPerformanceConfig(performanceConfig);
    }

    /**
     * 绩效模拟计算
     * @param simulationParam 绩效计算参数实体
     * @param bindingResult bindingResult
     * @return VO
     */
    @RequestMapping(value = "/simulation", method = RequestMethod.POST)
    @PreAuthorize("hasRole('but:performanceConfig:simulation')")
    public R info(@Validated SimulationParam simulationParam, BindingResult bindingResult) {
        // 入参校验结果
        if (bindingResult.hasErrors()) {
            return R.error(ParamValidateUtil.paramVilated(bindingResult));
        }
        return performanceConfigService.simulation(simulationParam);
    }

    /**
     * 对于生产岗位单独组装参数合并对象
     * @param dataList 绩效参数数据集
     * @param production 生产岗位绩效参数合并对象
     */
    private void buildProductionConfig(List<PerformanceConfig> dataList, PerformanceConfig production) {
        production.setPerformanceConfigIds(dataList.stream().sorted(Comparator.comparing(PerformanceConfig::getJob2))
                .map(PerformanceConfig::getPerformanceConfigId).map(StrUtil::toString).collect(Collectors.joining(CommonConstant.COMMA)));
        production.setJob1(dataList.get(0).getJob1());
        production.setExt1(dataList.get(0).getExt2());
        production.setExt2(dataList.get(0).getExt3());
        production.setExt3(dataList.get(0).getExt4());
        dataList.forEach(p -> {
            switch (NumUtil.null2Zero(p.getJob2())) {
                case CodeConstant.PRODUCTION_PLAN:
                    production.setExt4(p.getExt1());
                    break;
                case CodeConstant.PRODUCTION_UI:
                    production.setExt5(p.getExt1());
                    break;
                case CodeConstant.PRODUCTION_PROGRAM:
                    production.setExt6(p.getExt1());
                    break;
                case CodeConstant.PRODUCTION_CONTENT:
                    production.setExt7(p.getExt1());
                    break;
                case CodeConstant.PRODUCTION_HARDWARE:
                    production.setExt8(p.getExt1());
                    break;
                default:
                    break;
            }
        });
    }

    /**
     * 对于生产岗位单独拆分参数合并对象
     * @param production 生产岗位绩效参数合并对象
     * @param operationMode 操作模式
     * @return  dataList 生产绩效参数数据集
     */
    private List<PerformanceConfig> parseProductionConfig(PerformanceConfig production, String operationMode) {
        List<Long> performanceConfigIdList = new ArrayList<>();
        if (StrUtil.equals(operationMode, CommonConstant.UPDATE_MODE)) {
            if (StrUtil.isBlank(production.getPerformanceConfigIds())) {
                throw new RuntimeException("performanceConfigIds cannot be blank");
            }
            performanceConfigIdList = Arrays.stream(StrUtil.split(production.getPerformanceConfigIds(), CommonConstant.COMMA))
                    .map(Long::valueOf).collect(Collectors.toList());
            if (ListUtil.size(performanceConfigIdList) != 5) {
                throw new RuntimeException("performanceConfigIds size is incorrect");
            }
        }
        // 结果集
        List<PerformanceConfig> dataList = new ArrayList<>();
        // 策划组
        buildPerformanceConfig(dataList, performanceConfigIdList, production, new PerformanceConfig(), CodeConstant.PRODUCTION_PLAN, production.getExt4());
        // ui设计
        buildPerformanceConfig(dataList, performanceConfigIdList, production, new PerformanceConfig(), CodeConstant.PRODUCTION_UI, production.getExt5());
        // 程序组
        buildPerformanceConfig(dataList, performanceConfigIdList, production, new PerformanceConfig(), CodeConstant.PRODUCTION_PROGRAM, production.getExt6());
        // 内容组
        buildPerformanceConfig(dataList, performanceConfigIdList, production, new PerformanceConfig(), CodeConstant.PRODUCTION_CONTENT, production.getExt7());
        // 硬件组
        buildPerformanceConfig(dataList, performanceConfigIdList, production, new PerformanceConfig(), CodeConstant.PRODUCTION_HARDWARE, production.getExt8());
        // 返回结果集
        return dataList;

    }

    /**
     * 构建新增模式生产岗位绩效参数数据集
     * @param dataList 生产岗位绩效参数数据集
     * @param performanceConfigIdList 绩效参数id数据集
     * @param production 生产岗位绩效合并对象
     * @param performanceConfig 生产岗位绩效参数对象
     * @param job2 岗位二类
     * @param rate 生产岗位固定提成比例
     */
    private void buildPerformanceConfig(List<PerformanceConfig> dataList, List<Long> performanceConfigIdList, PerformanceConfig production,
                                        PerformanceConfig performanceConfig, Integer job2, BigDecimal rate) {
        if (!ListUtil.isEmpty(performanceConfigIdList)) {
            performanceConfig.setPerformanceConfigId(performanceConfigIdList.get(job2 - 4));
            performanceConfig.setUpdater(getUserId());
            performanceConfig.setUpdateTime(new Date());
        } else {
            performanceConfig.setCreator(getUserId());
            performanceConfig.setCreateTime(new Date());
        }
        performanceConfig.setYear(production.getYear());
        performanceConfig.setVersion(production.getVersion());
        performanceConfig.setJob1(CodeConstant.PERFORMANCE_PRODUCTION);
        performanceConfig.setJob2(job2);
        performanceConfig.setMarginRemovalRate(production.getMarginRemovalRate());
        performanceConfig.setNote(production.getNote());
        performanceConfig.setExt1(rate);
        performanceConfig.setExt2(production.getExt1());
        performanceConfig.setExt3(production.getExt2());
        performanceConfig.setExt4(production.getExt3());
        dataList.add(performanceConfig);
    }

}
